package com.itaming.lycheeframework.support.web;

import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.web.servlet.HandlerInterceptor;

/**
 * 请求唯一拦截器
 *
 * @author A.Ming
 */
public abstract class OncePerRequestInterceptor implements HandlerInterceptor {

    /**
     * 被拦截过标记属性名
     */
    private final String interceptedAttributeName = getClass().getName() + ".INTERCEPTED";

    /**
     * 预处理
     *
     * @param request  请求
     * @param response 响应
     * @param handler  处理器
     * @return boolean
     * @throws Exception 异常
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        if (request.getAttribute(interceptedAttributeName) != null) {
            return true;
        }

        request.setAttribute(interceptedAttributeName, Boolean.TRUE);

        return doPreHandle(request, response, handler);
    }

    /**
     * 预处理
     *
     * @param request  请求
     * @param response 响应
     * @param handler  处理器
     * @return boolean
     * @throws Exception 异常
     */
    protected abstract boolean doPreHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception;

    /**
     * 请求完成后的处理
     *
     * @param request  请求
     * @param response 响应
     * @param handler  处理器
     * @param ex       请求处理过程中抛出的异常
     * @throws Exception 异常
     */
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        // 备忘：
        // 当有全局异常处理@ControllerAdvice时，这里的异常ex为空
        // 在 DispatcherServlet 的 processHandlerException 方法中，会找到全局异常处理器处理异常
        try {
            doAfterCompletion(request, response, handler, ex);
        } finally {
            request.removeAttribute(interceptedAttributeName);
        }
    }

    /**
     * 请求完成后的处理
     *
     * @param request  请求
     * @param response 响应
     * @param handler  处理器
     * @param ex       请求处理过程中抛出的异常
     * @throws Exception 异常
     */
    protected void doAfterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {

    }

}
